﻿using System;
using System.Collections.Generic;
using NHibernate.Mapping.ByCode;
using Xenta.Enums;
using Xenta.Utils;

namespace Xenta.Entities
{
    /// <summary>
    /// Represents the generic attribute entity.
    /// </summary>
    /// <remarks>
    /// To define the concrete attribute, please use a string 
    /// based discriminator up to 10 characters.
    /// </remarks>
    public abstract class GenericAttributeEntity : AuditableEntity
    {
        #region Properties

        /// <summary>
        /// Gets or sets the holder identifier.
        /// </summary>
        public virtual int HolderID
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the key.
        /// </summary>
        public virtual string Key
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the value.
        /// </summary>
        public virtual string Value
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the flags value.
        /// </summary>
        public virtual int FlagsValue
        {
            get;
            set;
        }

        #endregion

        #region Methods

        /// <summary>
        /// Gets the attribute value converted into type T.
        /// </summary>
        /// <typeparam name="T">The target type to convert.</typeparam>
        /// <param name="defaultValue">The default value.</param>
        /// <returns>The value as type T.</returns>
        public virtual T ValueAs<T>(T defaultValue = default(T))
        {
            return Value.ParseAs(defaultValue);
        }

        #endregion

        #region Utilities

        protected override void Disclose(IDictionary<String, Object> obj,
            DisclosureLevel level,
            IDictionary<String, String> options)
        {
            base.Disclose(obj, level, options);
            if(level >= DisclosureLevel.Keys)
            {
                obj["HolderID"] = HolderID;
                obj["Key"] = Key;
            }
            if(level >= DisclosureLevel.Base)
                obj["Value"] = Value;
        }

        #endregion
    }

    /// <summary>
    /// The entity NHibernate mapper.
    /// </summary>
    public class GenericAttributeMapping : EntityMapping<GenericAttributeEntity>
    {
        /// <summary>
        /// Initializes a new class instance.
        /// </summary>
        public GenericAttributeMapping()
        {
            Table("fwk_GenericAttributes");
            Id(x => x.EntityID, m =>
            {
                m.Column("AttributeID");
                m.Generator(Generators.Identity);
            });
            Discriminator(m =>
            {
                m.Column("Discriminator");
                m.Length(10);
                m.Force(true);
                m.NotNullable(true);
            });
            Property(x => x.HolderID, m =>
            {
                m.NotNullable(true);
                m.Index("IX_fwk_GenericAttributes");
            });
            Property(x => x.Key, m =>
            {
                m.NotNullable(true);
                m.Length(100);
                m.Index("IX_fwk_GenericAttributes");
                m.Column(c =>
                {
                    c.Name("[Key]");
                    c.SqlType("nvarchar(100)");
                });
            });
            Property(x => x.Value, m =>
            {
                m.NotNullable(true);
                m.Length(1000);
                m.Column(c =>
                {
                    c.SqlType("nvarchar(4000)");
                });
            });
            Property(x => x.FlagsValue, m =>
            {
                m.Column("Flags");
                m.NotNullable(true);
            });
            Property(x => x.CreatedOn, m =>
            {
                m.NotNullable(true);
            });
            Property(x => x.UpdatedOn, m =>
            {
                m.NotNullable(true);
            });
            Cache(m =>
            {
                m.Usage(CacheUsage.ReadWrite);
            });
        }
    }
}
